#include <std.h>
#include <type.h>
#include <text.h>
#include <keyboard.h>
#include <asm.h>
#include <system.h>
#include <pio.h>
#include <dint.h>
#include <sched.h>
#include <dint.h>

/********************************Kernel Function File************************std.h*/
/*Least sanity checks in this file-- these fns are expected to work!*/

static int debugv=0;

kdrv *std_kbd=(kdrv *)0;

void debug()
{
	printk("DBG%d",debugv++);
}

void show_stack_frame(u32 *esp)
{
	int i;
	esp-=5;
	printk("\nStack frame:");
	for(i=-5;i<6;i++)	{
		printk("\n@ esp %d : 0x%x",i,*esp);
		esp++;
	}
}

unsigned abs(signed x)
{
	if(x>0)
		return (unsigned)x;
	else
		return (unsigned)(-x);
}

float fabs(float x)
{
	if(x>0)
		return x;
	else
		return (-x);
}

char *find_str_first(const char *string,const char *srch)
{
	const char *p;
	for(p=string;*p!=NULL;p++)	{
		if(!strcmp(p,srch))
			return (char *)p;
	}
	return NULL;
}

void * memset(void * s,char c,size_t count)
{
	char *xs = (char *) s;

	while (count--)
		*xs++ = c;
	return s;
}

char *strncpy(char *dest, const char *src, size_t count)
{
	char *tmp = dest;
	while (count) {
		if ((*tmp = *src) != 0)
			src++;
		tmp++;
		count--;
	}
	return dest;
}

char *strncpynull(char *dest, const char *src, size_t count)
{
	char *tmp = dest;
	while (count) {
		if ((*tmp = *src) != 0)
			src++;
		tmp++;
		count--;
	}
	*tmp=NULL;
	return dest;
}
	

char _ctype[] = {
_C,_C,_C,_C,_C,_C,_C,_C,			/* 0-7 */
_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C,		/* 8-15 */
_C,_C,_C,_C,_C,_C,_C,_C,			/* 16-23 */
_C,_C,_C,_C,_C,_C,_C,_C,			/* 24-31 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,			/* 32-39 */
_P,_P,_P,_P,_P,_P,_P,_P,			/* 40-47 */
_D,_D,_D,_D,_D,_D,_D,_D,			/* 48-55 */
_D,_D,_P,_P,_P,_P,_P,_P,			/* 56-63 */
_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U,	/* 64-71 */
_U,_U,_U,_U,_U,_U,_U,_U,			/* 72-79 */
_U,_U,_U,_U,_U,_U,_U,_U,			/* 80-87 */
_U,_U,_U,_P,_P,_P,_P,_P,			/* 88-95 */
_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L,	/* 96-103 */
_L,_L,_L,_L,_L,_L,_L,_L,			/* 104-111 */
_L,_L,_L,_L,_L,_L,_L,_L,			/* 112-119 */
_L,_L,_L,_P,_P,_P,_P,_C,			/* 120-127 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 128-143 */
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,		/* 144-159 */
_S|_SP,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,   /* 160-175 */
_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,_P,       /* 176-191 */
_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,_U,       /* 192-207 */
_U,_U,_U,_U,_U,_U,_U,_P,_U,_U,_U,_U,_U,_U,_U,_L,       /* 208-223 */
_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,_L,       /* 224-239 */
_L,_L,_L,_L,_L,_L,_L,_P,_L,_L,_L,_L,_L,_L,_L,_L};      /* 240-255 */


char *strupr(char *s)
{
	char *temp;
	temp=s;
	while(*s!=0)
	{
		*s=(*s-0x20);
		s++;
	}
	return temp;
}

size_t strspn(const char *s, const char *accept)
{
	const char *p;
	const char *a;
	size_t count = 0;

	for (p = s; *p != '\0'; ++p) {
		for (a = accept; *a != '\0'; ++a) {
			if (*p == *a)
				break;
		}
		if (*a == '\0')
			return count;
		++count;
	}

	return count;
}

int kbhit()
{
	char c;
	c=inb(0x64);
	return (c&1);
}

char bcd2binary(char al)
{
	char cl,ch;
	cl=al;
	cl=cl>>4;
	ch=cl;
	cl=cl<<3;
	cl+=ch;
	cl+=ch;
	al=al&0xf;
	al+=cl;
	return al;
}

size_t strlen(const char *str)
{
	size_t ret_val;
	for(ret_val = 0; *str != '\0'; str++)
		ret_val++;
	return ret_val;
}

/*Returns how many bytes to be allocated for the string... just adds one to strlen for the null character*/
size_t strmem(const char *str)
{
	size_t ret_val;
	for(ret_val = 0; *str != '\0'; str++)
		ret_val++;
	ret_val++;
	return ret_val;
}

size_t linelen(const char *str)
{
	size_t ret_val;
	for(ret_val=0;*str !='\n' && *str !='\0' ;str++)
		ret_val++;
	return ret_val;
}

int strcmp(const char *cs, const char *ct)
{
	signed char __res;
	while (1) {
		if ((__res = *cs - *ct++) != 0 || !*cs++)
			break;
	}
	return (int)__res;
}

int strncmp(const char *cs, const char *ct, size_t count)
{
	signed char __res = 0;

	while (count) {
		if ((__res = *cs - *ct++) != 0 || !*cs++)
			break;
		count--;
	}
	return __res;
}

int strfcmp(const char *cs,const char *ct)
{
	size_t count;
	count=strlen(ct);
	signed char __res = 0;

	while (count) {
		if ((__res = *cs - *ct++) != 0 || !*cs++)
			break;
		count--;
	}
	return __res;
}

char *strchr(const char *s, int c)
{
	for (; *s != (char)c; ++s)
		if (*s == '\0')
			return NULL;
	return (char *)s;
}

void *c_memcpy(void *dst_ptr, const void *src_ptr, size_t count)
{
	void *ret_val = dst_ptr;
	const char *src = (const char *)src_ptr;
	char *dst = (char *)dst_ptr;

	for(; count != 0; count--)
		*dst++ = *src++;
	return ret_val;
}

void memcpy(void * to, void * from, size_t n)
{
int d0, d1, d2;
__asm__ __volatile__(
	"rep ; movsl\n\t"
	"movl %4,%%ecx\n\t"
	"andl $3,%%ecx\n\t"
	"rep ; movsb\n\t"
	"1:"
	: "=&c" (d0), "=&D" (d1), "=&S" (d2)
	: "0" (n/4), "g" (n), "1" ((long) to), "2" ((long) from)
	: "memory");
}

void * __memset(void * s, char c,size_t count)
{
int d0, d1;
__asm__ __volatile__(
	"rep\n\t"
	"stosb"
	: "=&c" (d0), "=&D" (d1)
	:"a" (c),"1" (s),"0" (count)
	:"memory");
return s;
}

void * _memset(void * s, unsigned long c, size_t count)
{
int d0, d1;
__asm__ __volatile__(
	"rep ; stosl\n\t"
	"testb $2,%b3\n\t"
	"je 1f\n\t"
	"stosw\n"
	"1:\ttestb $1,%b3\n\t"
	"je 2f\n\t"
	"stosb\n"
	"2:"
	:"=&c" (d0), "=&D" (d1)
	:"a" (c), "q" (count), "0" (count/4), "1" ((long) s)
	:"memory");
return (s);	
}

void *memsetw(void *dst, int val, size_t count)
{
	char *temp = (char *)dst;

	for( ; count != 0; count--)
		*temp++ = val;
	return dst;
}

void clearmem(char *buffer,unsigned long count)
{
	while(--count>0)
		*buffer++=0;
}

unsigned long pow(unsigned long x,unsigned long y)
{
    unsigned long mfact;
    mfact=x;
	if(y==0)
	{
		return 1;
	}
	y--;
    while(y>0)
	{
		x*=mfact;
		y--;
	}
	return x;
}

unsigned long getnumber(char *buffer)
{
	char str_scan=0;
	char number_length=0;
	unsigned long number=0;
	if(*buffer=='0' && *(buffer+1)=='x')
	{
		buffer+=2;
		number_length=strlen(buffer);
		for(str_scan=0;str_scan<number_length;str_scan++)
		{
			if(*(buffer+str_scan)>=0x30 && *(buffer+str_scan)<=0x39)
			{
				number+=(pow(16,number_length-str_scan-1))*(*(buffer+str_scan)-0x30);
			}
			else if(*(buffer+str_scan)>=0x41 && *(buffer+str_scan)<=0x46)
			{
				number+=(pow(16,number_length-str_scan-1))*(*(buffer+str_scan)-0x37);
			}
			else if(*(buffer+str_scan)>=0x61 && *(buffer+str_scan)<=0x66)
			{
				number+=(pow(16,number_length-str_scan-1))*(*(buffer+str_scan)-0x57);
			}
		}
	}
	else
	{
		number_length=strlen(buffer);
		for(str_scan=0;str_scan<number_length;str_scan++)
		{
			number=number+(pow(10,number_length-str_scan-1))*(*(buffer+str_scan)-0x30);
		}
	}
	return number;
}

int getstringparameter(const char *buffer,char *ret_string,char separator,unsigned ret_sno)
{
	unsigned str_count=0,pcnt=0,ipcnt=0;
	while(str_count<=strlen(buffer))	{
		if(*(buffer+str_count)==separator && *(buffer+str_count+1)!=separator)	{
			pcnt++;
		} else	{
			if(pcnt==ret_sno)	{
				*(ret_string+ipcnt)=*(buffer+str_count);
				ipcnt++;
			}
		}
		str_count++;
	}
	*(ret_string+ipcnt)=0;
	return 0;
}

/*This function gets the string surrounded by start and end*/
int getstringenv(char *buffer,char *ret_string,char start,char end)
{
	unsigned i=0,slen,j=0;
	char t=0;
	slen=strlen(buffer);
	while(i<slen)	{
		if(*(buffer+i)==start)	{
			t=1;
			i++;
		}
		else if(*(buffer+i)==end)	{
			t=2;
			break;
		}
		if(t)	{
			*(ret_string+j)=*(buffer+i);
			j++;
		}
		i++;
	}
	*(ret_string+j)=0;
	if(t==2)
		return 0;
	else
		return -1;
}

int getparamcount(char *buffer,char separator)
{
	unsigned str_count=0,pcnt=0;
	while(str_count<=strlen(buffer))	{
		if(*(buffer+str_count)==separator && *(buffer+str_count+1)!=separator)	{
			pcnt++;
		}
		str_count++;
	}
	return pcnt;
}

unsigned getparam(char *buffer,char separator,unsigned ret_sno)
{
	char opt[50];
	getstringparameter(buffer,opt,separator,ret_sno);
	return getnumber(opt);
}

void strcpy(char *string1,char *string2)
{
	while(*string2!=0)
	{
		*string1++=*string2;
		string2++;
	}
	*string1=0;
}

static long int last_val;
static float rnd;
#define MODULUS		2147483647L
#define FACTOR          16807L
#define DIVISOR  	127773L
#define REMAINDER       2836L

long int random(void)
{
 long int last_div = last_val / DIVISOR;
 long int last_rem = last_val % DIVISOR;
 last_val = (FACTOR * last_rem) - (REMAINDER * last_div);
 if (last_val < 0) last_val += MODULUS;
 rnd=last_val/0x1000;
 return last_val;
}

void seed(long int seed)
{
    last_val = seed;
}

int do_printf(const char *fmt, va_list args, fnptr_t fn)
{
	unsigned state, flags, radix, actual_wd, count, given_wd;
	char *where, buf[PR_BUFLEN];
	long num;
	state = flags = count = given_wd = 0;
/* begin scanning format specifier list */
	for(; *fmt; fmt++)
	{
		switch(state)
		{
/* STATE 0: AWAITING % */
		case 0:
			if(*fmt != '%')	/* not %... */
			{
				fn(*fmt);	/* ...just echo it */
				count++;
				break;
			}
/* found %, get next char and advance state to check if next char is a flag */
			state++;
			fmt++;
			/* FALL THROUGH */
/* STATE 1: AWAITING FLAGS (%-0) */
		case 1:
			if(*fmt == '%')	/* %% */
			{
				fn(*fmt);
				count++;
				state = flags = given_wd = 0;
				break;
			}
			if(*fmt == '-')
			{
				if(flags & PR_LJ)/* %-- is illegal */
					state = flags = given_wd = 0;
				else
					flags |= PR_LJ;
				break;
			}
/* not a flag char: advance state to check if it's field width */
			state++;
/* check now for '%0...' */
			if(*fmt == '0')
			{
				flags |= PR_LZ;
				fmt++;
			}
			/* FALL THROUGH */
/* STATE 2: AWAITING (NUMERIC) FIELD WIDTH */
		case 2:
			if(*fmt >= '0' && *fmt <= '9')
			{
				given_wd = 10 * given_wd +
					(*fmt - '0');
				break;
			}
/* not field width: advance state to check if it's a modifier */
			state++;
			/* FALL THROUGH */
/* STATE 3: AWAITING MODIFIER CHARS (FNlh) */
		case 3:
			if(*fmt == 'F')
			{
				flags |= PR_FP;
				break;
			}
			if(*fmt == 'N')
				break;
			if(*fmt == 'l')
			{
				flags |= PR_32;
				break;
			}
			if(*fmt == 'h')
			{
				flags |= PR_16;
				break;
			}
/* not modifier: advance state to check if it's a conversion char */
			state++;
			/* FALL THROUGH */
/* STATE 4: AWAITING CONVERSION CHARS (Xxpndiuocs) */
		case 4:
			where = buf + PR_BUFLEN - 1;
			*where = '\0';
			switch(*fmt)
			{
			case 'X':
				flags |= PR_CA;
				/* FALL THROUGH */
/* xxx - far pointers (%Fp, %Fn) not yet supported */
			case 'x':
			case 'p':
			case 'n':
				radix = 16;
				goto DO_NUM;
			case 'd':
			case 'i':
				flags |= PR_SG;
				/* FALL THROUGH */
			case 'u':
				radix = 10;
				goto DO_NUM;
			case 'o':
				radix = 8;
/* load the value to be printed. l=long=32 bits: */
DO_NUM:				if(flags & PR_32)
					num = va_arg(args, unsigned long);
/* h=short=16 bits (signed or unsigned) */
				else if(flags & PR_16)
				{
					if(flags & PR_SG)
						num = va_arg(args, short);
					else
						num = va_arg(args, unsigned short);
				}
/* no h nor l: sizeof(int) bits (signed or unsigned) */
				else
				{
					if(flags & PR_SG)
						num = va_arg(args, int);
					else
						num = va_arg(args, unsigned int);
				}
/* take care of sign */
				if(flags & PR_SG)
				{
					if(num < 0)
					{
						flags |= PR_WS;
						num = -num;
					}
				}
/* convert binary to octal/decimal/hex ASCII
OK, I found my mistake. The math here is _always_ unsigned */
				do
				{
					unsigned long temp;

					temp = (unsigned long)num % radix;
					where--;
					if(temp < 10)
						*where = temp + '0';
					else if(flags & PR_CA)
						*where = temp - 10 + 'A';
					else
						*where = temp - 10 + 'a';
					num = (unsigned long)num / radix;
				}
				while(num != 0);
				goto EMIT;
			case 'c':
/* disallow pad-left-with-zeroes for %c */
				flags &= ~PR_LZ;
				where--;
				*where = (char)va_arg(args,
					char);
				actual_wd = 1;
				goto EMIT2;
			case 's':
/* disallow pad-left-with-zeroes for %s */
				flags &= ~PR_LZ;
				where = va_arg(args, char *);
EMIT:
				actual_wd = strlen(where);
				if(flags & PR_WS)
					actual_wd++;
/* if we pad left with ZEROES, do the sign now */
				if((flags & (PR_WS | PR_LZ)) ==
					(PR_WS | PR_LZ))
				{
					fn('-');
					count++;
				}
/* pad on left with spaces or zeroes (for right justify) */
EMIT2:				if((flags & PR_LJ) == 0)
				{
					while(given_wd > actual_wd)
					{
						fn(flags & PR_LZ ? '0' :
							' ');
						count++;
						given_wd--;
					}
				}
/* if we pad left with SPACES, do the sign now */
				if((flags & (PR_WS | PR_LZ)) == PR_WS)
				{
					fn('-');
					count++;
				}
/* emit string/char/converted number */
				while(*where != '\0')
				{
					fn(*where++);
					count++;
				}
/* pad on right with spaces (for left justify) */
				if(given_wd < actual_wd)
					given_wd = 0;
				else given_wd -= actual_wd;
				for(; given_wd; given_wd--)
				{
					fn(' ');
					count++;
				}
				break;
			default:
				break;
			}
		default:
			state = flags = given_wd = 0;
			break;
		}
	}
	return count;
}

int vprintf_help(unsigned int c)
{
	putchar_text(c);
	return 0 ;
} 

int vprintf_put_text(unsigned int c)
{
	putchar_text(c);
	return 0 ;
}

int vprintf(const char *fmt, va_list args)
{
	return do_printf(fmt, args, vprintf_help);
}

int vprintf_text(const char *fmt, va_list args)
{
	return do_printf(fmt, args, vprintf_put_text);
}

int printk(const char *fmt, ...)
{
	va_list args;
	int ret_val;
	va_start(args, fmt);
	ret_val = vprintf(fmt, args);
	va_end(args);
	return ret_val;
}

int text_print(const char *fmt, ...)
{
	static spin_lock_t printk_lock;
	acquire_spin_lock(&printk_lock);
	va_list args;
	int ret_val;
	va_start(args, fmt);
	ret_val = vprintf_text(fmt, args);
	va_end(args);
	release_spin_lock(&printk_lock);
	return ret_val;
}

int stop(const char *fmt, ...)
{
	va_list args;
	int ret_val;
	va_start(args, fmt);
	ret_val = vprintf(fmt,args);
	va_end(args);
	suspend_all();
	return ret_val;
}

int error(const char *fmt, ...)
{
	va_list args;
	int ret_val;
	va_start(args, fmt);
	ret_val = vprintf(fmt, args);
	va_end(args);
	mdelay(500);
	return ret_val;
}


/*Sane will be checking for the keyboard driver and using getch() in case it is up*/
void sane(unsigned i,const char *msg)
{
	if(i)
		error("\n%s",msg);
}

void showcursor(int type)
{
	char *f=(char *)0xb8000;
	char temp;
	unsigned short cur=0,cur2=0;
	cur2=getcursor();
	for(cur=0;cur<=2000;cur++)
	{
    	temp=*(f+cur*2+1);
    	if(cur==cur2)
    	{
    		*(f+cur*2+1)=type;
    	}
    	else
    	{
    		if(temp==type)
    		{
    			*(f+cur*2+1)=0x7;
    		}
    	}
    }
}

static int i=0;

void stdgetch_prepare()
{
	if(!std_kbd)	{
		std_kbd=get_device("kbd");
		if(std_kbd==0)
			stop("getch has no keyboard.");
	}
}

int getch()
{
	i=0;
	if(!std_kbd)	{
		std_kbd=get_device("kbd");
		if(std_kbd==0)
			stop("getch has no keyboard.");
	}
	while(1)	{
		i=std_kbd->read_device(READ_DEF,0,0,0);
		if(i)
			break;
	}
	return i;
}

char waitkey()
{

	i=0;
	while(!i)	{
		i=get_key();
	}
	return i;
}

int gets(char *kbuf,int inputlim)
{
	char *ret_buf;
	unsigned long inputlength=0;
	char usr_key;
	ret_buf=kbuf;
	inputlim++;
	while(1)
	{
		usr_key=getch();
		if(usr_key==0xa)
		{
			break;
		}
		else if(usr_key==-1)
		{
			if(inputlength<inputlim)	{
				inputlength++;
				*kbuf++='\n';
				printk("\n");
			}
		}
		else if(usr_key==9)
		{
		}
		else if(usr_key==8)
		{
			if(inputlength>0)
			{
				inputlength--;
				movecursor(-1);
				putchar_text(0);
					movecursor(-1);
				*kbuf--=0;
			}
		}			
		else
		{
			if(inputlength<inputlim)	{
				inputlength++;
				*kbuf++=usr_key;
				putchar_text(usr_key);
			}
		}
	}
	*kbuf++=0;
	kbuf=ret_buf;
	showcursor(0x7);
	return 1;
}
	

void print_num(unsigned long number)
{
	 unsigned long divhex=0x10000000;
	 char reshex=0;
	 char uzerohex=0;
	 printk("\n");
	 putchar_text(0x30);
	 putchar_text(0x78);
	 while(divhex!=0)
	 {
	 	reshex=number/divhex;
	 	if(reshex==0)
	 	{
	 		if(uzerohex!=0)
	 		{
	 			putchar_text(0x30);
	 		}
	 	}
	 	else
	 	{
	 		uzerohex=1;
	 		if(reshex<0xa)
	 		{
	 		 	putchar_text(reshex+0x30);
	 	    }
	 	    else
	 	    {
	 	    	putchar_text(reshex+55);
	 	    }
	 	}	
	 	number=number%divhex;
	 	divhex=divhex/16;
	 }
	 if(uzerohex==0)
	 {
	 	putchar_text(0x30);
	 }	
}

void print_mem(unsigned char *start,unsigned long len)
{
	printk("\n");
	while(--len>0)	{
		printk(" %x ",(u8)(*start++));
	}
}

void print_memd(u32 *start,unsigned long len)
{
	printk("\n");
	while(--len>0)	{
		printk(" %x ",(u32)(*start++));
	}
}

void puts(char *s)
{
	printk("\n%s",s);
}

int int86(int intno,union REGS *inregs,union REGS *outregs)
{
	unsigned int cf=0;
	_bioscall(inregs->x.ax,inregs->x.bx,inregs->x.cx,inregs->x.dx,inregs->x.si,inregs->x.di,intno);
	cf=_f&1;
	outregs->x.ax=(u16)_eax;
	outregs->x.bx=(u16)_ebx;
	outregs->x.cx=(u16)_ecx;
	outregs->x.dx=(u16)_edx;
	outregs->x.si=(u16)_esi;
	outregs->x.di=(u16)_edi;
	outregs->x.flags=_f;
	outregs->x.cflag=cf;
	return (int)_f;
}

int isnum(char *s)
{
	while(1) {
		if(*s<0x30 || *s>0x39)
			return (int)*s;
		s++;
	}
	return 0;
}

#define ASCEND 	2
#define DESCEND	1

int swapch(char *s1,char *s2)
{
	char x;
	x=*s1;
	*s1=*s2;
	*s2=x;
	return 0;
}

int bubblesort(char *s,unsigned long len,char order)	
{
	unsigned long i,j;
	switch(order)	{
		case ASCEND:	{
			for(j=len;j>0;j--)	{
				for(i=0;i<j;i++)	{
						if(s[i]>s[i+1])
							swapch(&s[i],&s[i+1]);
				}
			}
		}
		case DESCEND:	{
			for(j=len;j>0;j--)	{
				for(i=0;i<j;i++)	{
						if(s[i]<s[i+1])
							swapch(&s[i],&s[i+1]);
				}
			}
		}
		default:return 1;
	}
	return 0;
}

int scan_num(int *num)
{
	char usr[20];
	gets(usr,20);
	*num=getnumber(usr);
	return 0;
}

int biosequip()
{
	_bioscall(0,0,0,0,0,0,0x11);
	return (u16)_eax;
}

int biosmemsize()
{
	_bioscall(0,0,0,0,0,0,0x12);
	return (u16)_eax;
}

void memswp(char *i,char *j,size_t size)
{
	char tmp;
	do	{
		tmp=*i;
		*i++=*j;
		*j++=tmp;
	} while(--size);
}

#define T 7

void qsort( void * base, size_t nmemb, size_t size, int (*compar)( const void *, const void * ) )
{
    char * i;
    char * j;
    size_t thresh     = T * size;
    char * base_      = (char *)base;
    char * limit      = base_ + nmemb * size;

    if ( ( nmemb == 0 ) || ( size == 0 ) || ( base == NULL ) )
    {
        return;
    }

    for ( ;; )
    {
        if ( (unsigned )(limit - base_) > thresh ) /* QSort for more than T elements. */
        {
            /* We work from second to last - first will be pivot element. */
            i = base_ + size;
            j = limit - size;
            /* We swap first with middle element, then sort that with second
            and last element so that eventually first element is the median
            of the three - avoiding pathological pivots.
            */
            memswp( ( ( ( (size_t)( limit - base_ ) ) / size ) / 2 ) * size + base_, base_, size );
            if ( compar( i, j ) > 0 ) 
            	memswp( i, j, size );
            if ( compar( base_, j ) > 0 ) 
            	memswp( base_, j, size );
            if ( compar( i, base_ ) > 0 ) 
            	memswp( i, base_, size );
            /* Now we have the median for pivot element, entering main Quicksort. */
            for ( ;; )
            {
                do
                {
                    /* move i right until *i >= pivot */
                    i += size;
                } while ( compar( i, base_ ) < 0 );
                do
                {
                    /* move j left until *j <= pivot */
                    j -= size;
                } while ( compar( j, base_ ) > 0 );
                if ( i > j )
                {
                    /* break loop if pointers crossed */
                    break;
                }
                /* else swap elements, keep scanning */
                memswp( i, j, size );
            }
            /* move pivot into correct place */
            memswp( base_, j, size );
            /* recurse into larger subpartition, iterate on smaller */
            if ( j - base_ > limit - i )
            {
                /* left is larger */
                qsort( base, ( j - base_ ) / size, size, compar );
                base_ = i;
            }
            else
            {
                /* right is larger */
                qsort( i, ( limit - i ) / size, size, compar );
                limit = j;
            }
        }
        else /* insertion sort for less than T elements              */
        {
            for ( j = base_, i = j + size; i < limit; j = i, i += size )
            {
                for ( ; compar( j, j + size ) > 0; j -= size )
                {
                    memswp( j, j + size, size );
                    if ( j == base_ )
                    {
                        break;
                    }
                }
            }
            break;
        }
    }
    return;
}


int compareq( const void * left, const void * right )
{
    return *( (char *)left ) - *( (char *)right );
}

char * strcat( char *s1, const char *s2 )
{
    char * rc = s1;
    if ( *s1 )
    {
        while ( *++s1 );
    }
    while ( (*s1++ = *s2++) );
    return rc;
}

void *MK_FP(unsigned seg,unsigned ofs)
{
	return (void *)(seg*0x10+ofs);
}

int acquire_spin_lock(spin_lock_t *spin)
{
	while((*spin)==SPINSTATE);
	*spin=SPINSTATE;
	return NULL;
}

int release_spin_lock(spin_lock_t *spin)
{
	*spin=SPINRELEASE;
	return NULL;
}

void *flat(void *ptr)
{
	u16 seg,off;
	void *flat;
	off=(u16)(u32)(ptr);
    seg=(u16)((u32)(ptr)>>16);
    flat=(void *)(seg*0x10+off);
    return flat;
}

static unsigned long ltbm=0;
void tbm()
{
	printk("[TBM:%d]",_SYSTEM_READ_TIMER()-ltbm);
	ltbm=_SYSTEM_READ_TIMER();
}

void reset_tbm()
{
	ltbm=_SYSTEM_READ_TIMER();
}	
